package com.kexio.auth.config;

import java.time.Duration;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * Kexio权限框架配置属性
 * 
 * 绑定配置文件中的权限相关配置项，
 * 提供类型安全的配置访问和默认值管理。
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@ConfigurationProperties(prefix = "kexio.auth")
public class SecurityProperties {
    
    /**
     * 是否启用权限框架
     */
    private boolean enabled = true;
    
    /**
     * JWT配置
     */
    private Jwt jwt = new Jwt();
    
    /**
     * 会话配置
     */
    private Session session = new Session();
    
    /**
     * 缓存配置
     */
    private Cache cache = new Cache();
    
    /**
     * 安全配置
     */
    private Security security = new Security();
    
    /**
     * Web配置
     */
    private Web web = new Web();
    
    /**
     * 多租户配置
     */
    private Tenant tenant = new Tenant();
    
    /**
     * 事件配置
     */
    private Events events = new Events();
    
    /**
     * 审计配置
     */
    private Audit audit = new Audit();
    
    // ==================== JWT配置 ====================
    
    public static class Jwt {
        /**
         * JWT密钥
         */
        private String secret = "kexio-jwt-secret-key";
        
        /**
         * JWT算法
         */
        private String algorithm = "HS256";
        
        /**
         * 签发者
         */
        private String issuer = "kexio-system";
        
        /**
         * Access Token有效期
         */
        private Duration accessTokenExpire = Duration.ofHours(2);
        
        /**
         * Refresh Token有效期
         */
        private Duration refreshTokenExpire = Duration.ofDays(7);
        
        /**
         * 是否包含JTI
         */
        private boolean includeJti = true;
        
        /**
         * 时钟偏移容忍度
         */
        private Duration acceptClockSkew = Duration.ofMinutes(2);
        
        /**
         * 密钥轮换周期
         */
        private Duration keyRotation = Duration.ofDays(7);
        
        /**
         * 是否启用刷新令牌旋转
         */
        private boolean refreshRotation = false;
        
        // Getter/Setter
        public String getSecret() { return secret; }
        public void setSecret(String secret) { this.secret = secret; }
        public String getAlgorithm() { return algorithm; }
        public void setAlgorithm(String algorithm) { this.algorithm = algorithm; }
        public String getIssuer() { return issuer; }
        public void setIssuer(String issuer) { this.issuer = issuer; }
        public Duration getAccessTokenExpire() { return accessTokenExpire; }
        public void setAccessTokenExpire(Duration accessTokenExpire) { this.accessTokenExpire = accessTokenExpire; }
        public Duration getRefreshTokenExpire() { return refreshTokenExpire; }
        public void setRefreshTokenExpire(Duration refreshTokenExpire) { this.refreshTokenExpire = refreshTokenExpire; }
        public boolean isIncludeJti() { return includeJti; }
        public void setIncludeJti(boolean includeJti) { this.includeJti = includeJti; }
        public Duration getAcceptClockSkew() { return acceptClockSkew; }
        public void setAcceptClockSkew(Duration acceptClockSkew) { this.acceptClockSkew = acceptClockSkew; }
        public Duration getKeyRotation() { return keyRotation; }
        public void setKeyRotation(Duration keyRotation) { this.keyRotation = keyRotation; }
        public boolean isRefreshRotation() { return refreshRotation; }
        public void setRefreshRotation(boolean refreshRotation) { this.refreshRotation = refreshRotation; }
    }
    
    // ==================== 会话配置 ====================
    
    public static class Session {
        /**
         * 会话超时时间
         */
        private Duration timeout = Duration.ofHours(2);
        
        /**
         * 每个用户最大并发会话数
         */
        private int maxSessionsPerUser = 5;
        
        /**
         * 是否启用并发控制
         */
        private boolean enableConcurrentControl = true;
        
        /**
         * 会话踢出策略：KICK_OUT_BEFORE-踢出之前登录的，KICK_OUT_AFTER-踢出之后登录的
         */
        private String kickoutStrategy = "KICK_OUT_BEFORE";
        
        // Getter/Setter
        public Duration getTimeout() { return timeout; }
        public void setTimeout(Duration timeout) { this.timeout = timeout; }
        public int getMaxSessionsPerUser() { return maxSessionsPerUser; }
        public void setMaxSessionsPerUser(int maxSessionsPerUser) { this.maxSessionsPerUser = maxSessionsPerUser; }
        public boolean isEnableConcurrentControl() { return enableConcurrentControl; }
        public void setEnableConcurrentControl(boolean enableConcurrentControl) { this.enableConcurrentControl = enableConcurrentControl; }
        public String getKickoutStrategy() { return kickoutStrategy; }
        public void setKickoutStrategy(String kickoutStrategy) { this.kickoutStrategy = kickoutStrategy; }
    }
    
    // ==================== 缓存配置 ====================
    
    public static class Cache {
        /**
         * 是否启用缓存
         */
        private boolean enabled = true;
        
        /**
         * L1缓存配置
         */
        private L1 l1 = new L1();
        
        /**
         * L2缓存配置
         */
        private L2 l2 = new L2();
        
        public static class L1 {
            private boolean enabled = true;
            private int maxSize = 10000;
            private Duration expireAfterWrite = Duration.ofMinutes(5);
            private Duration refreshAfterWrite = Duration.ofMinutes(3);
            
            public boolean isEnabled() { return enabled; }
            public void setEnabled(boolean enabled) { this.enabled = enabled; }
            public int getMaxSize() { return maxSize; }
            public void setMaxSize(int maxSize) { this.maxSize = maxSize; }
            public Duration getExpireAfterWrite() { return expireAfterWrite; }
            public void setExpireAfterWrite(Duration expireAfterWrite) { this.expireAfterWrite = expireAfterWrite; }
            public Duration getRefreshAfterWrite() { return refreshAfterWrite; }
            public void setRefreshAfterWrite(Duration refreshAfterWrite) { this.refreshAfterWrite = refreshAfterWrite; }
        }
        
        public static class L2 {
            private boolean enabled = false;
            private Duration expireAfterWrite = Duration.ofMinutes(30);
            private String keyPrefix = "kexio:auth:";
            
            public boolean isEnabled() { return enabled; }
            public void setEnabled(boolean enabled) { this.enabled = enabled; }
            public Duration getExpireAfterWrite() { return expireAfterWrite; }
            public void setExpireAfterWrite(Duration expireAfterWrite) { this.expireAfterWrite = expireAfterWrite; }
            public String getKeyPrefix() { return keyPrefix; }
            public void setKeyPrefix(String keyPrefix) { this.keyPrefix = keyPrefix; }
        }
        
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        public L1 getL1() { return l1; }
        public void setL1(L1 l1) { this.l1 = l1; }
        public L2 getL2() { return l2; }
        public void setL2(L2 l2) { this.l2 = l2; }
    }
    
    // ==================== 安全配置 ====================
    
    public static class Security {
        /**
         * 密码配置
         */
        private Password password = new Password();
        
        /**
         * 登录配置
         */
        private Login login = new Login();

        /**
         * 权限相关配置
         */
        private Permissions permissions = new Permissions();
        
        public static class Password {
            private int minLength = 8;
            private int maxLength = 32;
            private boolean requireNumber = true;
            private boolean requireLetter = true;
            private boolean requireSpecial = false;
            private boolean requireUppercase = false;
            private boolean requireLowercase = false;
            private int historyCount = 5;
            private int expireDays = 90;
            
            public int getMinLength() { return minLength; }
            public void setMinLength(int minLength) { this.minLength = minLength; }
            public int getMaxLength() { return maxLength; }
            public void setMaxLength(int maxLength) { this.maxLength = maxLength; }
            public boolean isRequireNumber() { return requireNumber; }
            public void setRequireNumber(boolean requireNumber) { this.requireNumber = requireNumber; }
            public boolean isRequireLetter() { return requireLetter; }
            public void setRequireLetter(boolean requireLetter) { this.requireLetter = requireLetter; }
            public boolean isRequireSpecial() { return requireSpecial; }
            public void setRequireSpecial(boolean requireSpecial) { this.requireSpecial = requireSpecial; }
            public boolean isRequireUppercase() { return requireUppercase; }
            public void setRequireUppercase(boolean requireUppercase) { this.requireUppercase = requireUppercase; }
            public boolean isRequireLowercase() { return requireLowercase; }
            public void setRequireLowercase(boolean requireLowercase) { this.requireLowercase = requireLowercase; }
            public int getHistoryCount() { return historyCount; }
            public void setHistoryCount(int historyCount) { this.historyCount = historyCount; }
            public int getExpireDays() { return expireDays; }
            public void setExpireDays(int expireDays) { this.expireDays = expireDays; }
        }
        
        public static class Login {
            private int failureMaxAttempts = 5;
            private int failureLockMinutes = 30;
            private int captchaAfterFailures = 3;
            
            public int getFailureMaxAttempts() { return failureMaxAttempts; }
            public void setFailureMaxAttempts(int failureMaxAttempts) { this.failureMaxAttempts = failureMaxAttempts; }
            public int getFailureLockMinutes() { return failureLockMinutes; }
            public void setFailureLockMinutes(int failureLockMinutes) { this.failureLockMinutes = failureLockMinutes; }
            public int getCaptchaAfterFailures() { return captchaAfterFailures; }
            public void setCaptchaAfterFailures(int captchaAfterFailures) { this.captchaAfterFailures = captchaAfterFailures; }
        }
        
        /**
         * 权限配置
         */
        public static class Permissions {
            /**
             * 是否启用基础权限（所有用户默认拥有）
             */
            private boolean enableBase = false;
            
            /**
             * 基础权限列表
             */
            private java.util.List<String> base = java.util.List.of(
                "system:ping",
                "auth:logout"
            );
            
            /**
             * 是否启用“角色→默认权限”的推断
             * 关闭后，不再基于角色映射附加默认权限，仅使用后端查询得到的真实权限集合
             */
            private boolean enableRoleDefaults = false;
            
            public boolean isEnableBase() { return enableBase; }
            public void setEnableBase(boolean enableBase) { this.enableBase = enableBase; }
            public java.util.List<String> getBase() { return base; }
            public void setBase(java.util.List<String> base) { this.base = base; }
            public boolean isEnableRoleDefaults() { return enableRoleDefaults; }
            public void setEnableRoleDefaults(boolean enableRoleDefaults) { this.enableRoleDefaults = enableRoleDefaults; }
        }

        /**
         * 是否在权限校验切面中自动聚合数据权限（在未显式使用@DataScope时）
         */
        private boolean aggregatePermissionWithDataScope = true;

        public boolean isAggregatePermissionWithDataScope() { return aggregatePermissionWithDataScope; }
        public void setAggregatePermissionWithDataScope(boolean aggregatePermissionWithDataScope) { this.aggregatePermissionWithDataScope = aggregatePermissionWithDataScope; }
        
        public Password getPassword() { return password; }
        public void setPassword(Password password) { this.password = password; }
        public Login getLogin() { return login; }
        public void setLogin(Login login) { this.login = login; }
        public Permissions getPermissions() { return permissions; }
        public void setPermissions(Permissions permissions) { this.permissions = permissions; }
    }
    
    // ==================== Web配置 ====================
    
    public static class Web {
        /**
         * 是否启用Web支持
         */
        private boolean enabled = true;
        
        /**
         * 跨域配置
         */
        private Cors cors = new Cors();
        
        /**
         * 白名单
         */
        private List<String> whitelist = List.of(
            "/api/auth/login",
            "/api/auth/logout", 
            "/api/auth/captcha",
            "/actuator/**",
            "/swagger-ui/**",
            "/v3/api-docs/**"
        );
        
        public static class Cors {
            private boolean enabled = true;
            private List<String> allowedOrigins = List.of("*");
            private List<String> allowedMethods = List.of("GET", "POST", "PUT", "DELETE", "OPTIONS");
            private List<String> allowedHeaders = List.of("*");
            private boolean allowCredentials = false;
            
            public boolean isEnabled() { return enabled; }
            public void setEnabled(boolean enabled) { this.enabled = enabled; }
            public List<String> getAllowedOrigins() { return allowedOrigins; }
            public void setAllowedOrigins(List<String> allowedOrigins) { this.allowedOrigins = allowedOrigins; }
            public List<String> getAllowedMethods() { return allowedMethods; }
            public void setAllowedMethods(List<String> allowedMethods) { this.allowedMethods = allowedMethods; }
            public List<String> getAllowedHeaders() { return allowedHeaders; }
            public void setAllowedHeaders(List<String> allowedHeaders) { this.allowedHeaders = allowedHeaders; }
            public boolean isAllowCredentials() { return allowCredentials; }
            public void setAllowCredentials(boolean allowCredentials) { this.allowCredentials = allowCredentials; }
        }
        
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        public Cors getCors() { return cors; }
        public void setCors(Cors cors) { this.cors = cors; }
        public List<String> getWhitelist() { return whitelist; }
        public void setWhitelist(List<String> whitelist) { this.whitelist = whitelist; }
    }
    
    // ==================== 其他配置类 ====================
    
    public static class Tenant {
        private boolean enabled = false;
        private java.util.List<String> ignoreTables = java.util.List.of();
        /**
         * 是否允许在启用多租户时，登录请求未提供租户时回退到 "default" 租户。
         * 生产环境建议关闭。
         */
        private boolean allowDefaultFallback = true;
        
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        public java.util.List<String> getIgnoreTables() { return ignoreTables; }
        public void setIgnoreTables(java.util.List<String> ignoreTables) { this.ignoreTables = ignoreTables; }
        public boolean isAllowDefaultFallback() { return allowDefaultFallback; }
        public void setAllowDefaultFallback(boolean allowDefaultFallback) { this.allowDefaultFallback = allowDefaultFallback; }
    }
    
    public static class Events {
        private boolean enabled = false;
        
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
    }
    
    public static class Audit {
        private boolean enabled = true;
        
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
    }
    
    // ==================== 主要属性的Getter/Setter ====================
    
    public boolean isEnabled() { return enabled; }
    public void setEnabled(boolean enabled) { this.enabled = enabled; }
    public Jwt getJwt() { return jwt; }
    public void setJwt(Jwt jwt) { this.jwt = jwt; }
    public Session getSession() { return session; }
    public void setSession(Session session) { this.session = session; }
    public Cache getCache() { return cache; }
    public void setCache(Cache cache) { this.cache = cache; }
    public Security getSecurity() { return security; }
    public void setSecurity(Security security) { this.security = security; }
    public Web getWeb() { return web; }
    public void setWeb(Web web) { this.web = web; }
    public Tenant getTenant() { return tenant; }
    public void setTenant(Tenant tenant) { this.tenant = tenant; }
    public Events getEvents() { return events; }
    public void setEvents(Events events) { this.events = events; }
    public Audit getAudit() { return audit; }
    public void setAudit(Audit audit) { this.audit = audit; }
}
